package com.easyOrder.service.requisition;

import com.easyOrder.core.comm.BeanMapper;
import com.easyOrder.core.context.WebSession;
import com.easyOrder.core.exception.api.InvalidOprationException;
import com.easyOrder.core.utils.WebUtils;
import com.easyOrder.dao.RequisitionDetailMapper;
import com.easyOrder.dao.RequisitionMapper;
import com.easyOrder.dto.RequisitionDTO;
import com.easyOrder.dto.RequisitionDetailDTO;
import com.easyOrder.model.*;
import com.easyOrder.param.requisition.RequisitionParam;
import com.easyOrder.param.requisition.RequisitionParamDetail;
import com.easyOrder.service.ISequenceService;
import com.easyOrder.service.enums.InvoiceTypes;
import com.easyOrder.service.enums.RequisitionDetailState;
import com.easyOrder.service.enums.RequisitionState;
import com.easyOrder.service.enums.SeqType;
import com.easyOrder.service.material.MaterialService;
import com.easyOrder.service.record.DocumentChangeRecordService;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.AtomicDouble;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.text.MessageFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * Created by liutao on 2017/7/20.
 */
@Service
public class RequisitionService {

    @Autowired
    private RequisitionMapper requisitionMapper;

    @Autowired
    private RequisitionDetailService requisitionDetailService;

    @Autowired
    private RequisitionDetailMapper requisitionDetailMapper;

    @Autowired
    private ISequenceService sequenceService;

    @Autowired
    private DocumentChangeRecordService documentChangeRecordService;

    @Autowired
    private MaterialService materialService;

    @Autowired
    private RedisTemplate<String, Boolean> springRedisTemplate;


    /**
     * 添加订单
     *
     * @param requisition
     * @return
     */
    public Long add(RequisitionParam requisition) {
        WebSession session = requisition.getSession();
        requisition.setCode(requisition.getCode() == null ? "10000" : requisition.getCode() + requisition.getId());
        requisition.setCreatedDate(new Date());
        requisition.setCreaterId(session == null ? null : session.getUserId());
        requisition.setCreatedEmployeeId(session == null ? null : session.getEmployeeId());
        requisition.setModifierId(session == null ? null : session.getUserId());
        requisition.setModifiedEmployeeId(session == null ? null : session.getEmployeeId());
        requisition.setModifiedDate(new Date());
        requisition.setRequisitionerId(session == null ? null : session.getUserId());
        requisition.setRequisitionerEmployeeId(session == null ? null : session.getEmployeeId());
        requisition.setStatusId(RequisitionState.order.getValue());

        // build department and material mappings
        Set<Long> materialIds = Sets.newHashSet();
        requisition.getItems().forEach(item -> materialIds.add(item.getMaterialId()));
        Map<Long, Material> map = materialService.buildValidMapByIds(materialIds);
        StringBuilder logInfo = new StringBuilder();
        AtomicDouble totalAmount = new AtomicDouble(0);
        for (int i = 0; i < requisition.getItems().size(); i++) {
            RequisitionParamDetail item = requisition.getItems().get(i);
            item.setTenantId(requisition.getTenantId());
            item.setDocumentId(requisition.getId());
            item.setTag(requisition.getTag());
            item.setPrice(map.get(item.getMaterialId()).getPrice());
            item.setAmount(map.get(item.getMaterialId()).getPrice().multiply(item.getQuantity()));
            item.setOrdinal(i + 1);
            item.setStatusId(RequisitionDetailState.order.getValue());
            logInfo.append(MessageFormat.format("{0} {1}份, ", item.getMaterialName(), item.getQuantity()));
            //修改商品余量
            Material material = new Material();
            material.setId(item.getMaterialId());
            material.setQuantityOfResidue(map.get(item.getMaterialId()).getQuantityOfResidue().subtract(item.getQuantity()));
            materialService.updateMaterial(material);

            totalAmount.addAndGet(item.getAmount().doubleValue());
        }
        requisition.setAmount(new BigDecimal(totalAmount.get()).setScale(2, BigDecimal.ROUND_HALF_UP));
        requisitionMapper.insert(requisition);
        requisitionDetailMapper.batchInsert(requisition.getItems());
        addInvoiceLog(requisition.getId(), requisition.getTenantId(),
                MessageFormat.format("{0} 申购成功: {1}", requisition.getSession() == null ? "未知" : requisition.getSession().getUserName(),
                        logInfo.toString()));

        return requisition.getId();
    }

    /**
     * 通过主键查询订单
     *
     * @param id
     * @return
     */
    public Requisition findById(Long id) {
        Requisition requisition = requisitionMapper.selectByPrimaryKey(id);
        return requisition;
    }


    /**
     * 添加单据日志
     *
     * @param requisitionId
     * @param tenantId
     * @param content
     * @return
     */
    public int addInvoiceLog(Long requisitionId, Long tenantId, String content) {
        DocumentChangeRecord log = new DocumentChangeRecord();
        log.setChangeContent(content);
        log.setChangeDate(new Date());
        log.setDetailId(0L);
        log.setDocumentId(requisitionId);
        log.setDocumentTypeId(InvoiceTypes.requisition.getValue());
        log.setId(sequenceService.newKey(SeqType.DocumentChangeRecord));
        log.setTenantId(tenantId);
        return documentChangeRecordService.add(log);
    }

    /**
     * 修改状态
     *
     * @param
     * @param
     */
    public void updateRequisitionState(Long id, Integer requisitionState, Integer requisitionDetailState,String cancelReason) {
        //修改主单
        Requisition requisition = new Requisition();
        requisition.setId(id);
        requisition.setStatusId(requisitionState);
        requisition.setCancelReason(cancelReason);
        Date d = new Date();
        //如果是支付状态，修改支付时间
        if (requisitionState == RequisitionState.pay.getValue()) {
            requisition.setDeliveryDate(d);
        }
        requisition.setModifiedDate(d);
        requisitionMapper.updateByPrimaryKeySelective(requisition);

        //修改主单下的明细
        RequisitionDetail requisitionDetail = new RequisitionDetail();
        requisitionDetail.setStatusId(requisitionDetailState);
        requisitionDetail.setCancelReason(cancelReason);
        //如果是已接单状态，修改接单人
        if (requisitionDetailState == RequisitionDetailState.receiving.getValue()) {
            requisitionDetail.setReceiverId(WebUtils.Session.get().getUserId());
            requisitionDetail.setReceiverName(WebUtils.Session.get().getUserName());
        }
        RequisitionDetailExample example = new RequisitionDetailExample();
        example.createCriteria().andDocumentIdEqualTo(id).andStatusIdNotEqualTo(RequisitionDetailState.canceled.getValue());
        requisitionDetailMapper.updateByExampleSelective(requisitionDetail, example);

        //清楚缓存
        Requisition r = findById(id);
        String key = "requisition_" + r.getTag() + "-" + r.getBranchId();

        if (springRedisTemplate.hasKey(key)) {
            springRedisTemplate.delete(key);
        }

    }

    /**
     * 取消訂單
     *
     * @param requisitionId
     */
    public void cancelOrder(Long requisitionId) {
        RequisitionDetailExample example = new RequisitionDetailExample();
        example.createCriteria().andDocumentIdEqualTo(requisitionId);
        List<RequisitionDetail> requisitionDetails = requisitionDetailMapper.selectByExample(example);
        Set<Long> materialIds = requisitionDetails.stream().map(requisitionDetail -> requisitionDetail.getMaterialId()).collect(Collectors.toSet());
        Map<Long, Material> map = materialService.buildValidMapByIds(materialIds);
        if (CollectionUtils.isNotEmpty(requisitionDetails)) {
            requisitionDetails.forEach(item -> {
                Material material = new Material();
                material.setId(item.getMaterialId());
                material.setQuantityOfResidue(map.get(item.getMaterialId()).getQuantityOfResidue().add(item.getQuantity()));
                materialService.updateMaterial(material);
            });
        }

        updateRequisitionState(requisitionId, RequisitionState.canceled.getValue(), RequisitionDetailState.canceled.getValue(),"未付款");

    }

    /**
     * 客户完成订单
     * @param requisitionId
     */
    public void completeOrder(Long requisitionId){
        updateRequisitionState(requisitionId, RequisitionState.customerCompleted.getValue(), RequisitionDetailState.customerCompleted.getValue(),null);
    }


    /**
     * 通过门店查询订单
     *
     * @param branchId
     * @return
     */
    public List<RequisitionDTO> findByBranchId(Long branchId, List<Integer> states) {
        RequisitionExample example = new RequisitionExample();
        RequisitionExample.Criteria criteria = example.createCriteria();
        criteria.andBranchIdEqualTo(branchId);
        if (CollectionUtils.isNotEmpty(states)) {
            criteria.andStatusIdIn(states);
        }
        example.setOrderByClause(" delivery_date asc");
        List<Requisition> requisitions = requisitionMapper.selectByExample(example);
        List<RequisitionDTO> requisitionDTOS = BeanMapper.mapList(requisitions, RequisitionDTO.class);
        return requisitionDTOS;
    }

    /**
     * 接单（整单）
     */
    public List<RequisitionDetailDTO> getReceiver(Long requisitionId) {
        updateRequisitionState(requisitionId, RequisitionState.receiving.getValue(), RequisitionDetailState.receiving.getValue(),null);
        return requisitionDetailService.getRequisitionDetailDTOS(requisitionId);
    }



    public void updateRequisitionState(Long requisitionId, Integer state) {
        //修改主单
        Requisition requisition = new Requisition();
        requisition.setId(requisitionId);
        requisition.setStatusId(state);
        requisition.setModifiedDate(new Date());
        requisitionMapper.updateByPrimaryKeySelective(requisition);
    }

    /**
     * 接单（部分）
     */
    public void getReceiverByDetail(Long requisitionId, Long detailId) {
        requisitionDetailService.updateRequisitionDetail(detailId, RequisitionDetailState.receiving.getValue());
        int count = requisitionDetailService.findByStateCount(requisitionId, RequisitionDetailState.pay.getValue());
        if (count > 0) {
            updateRequisitionState(requisitionId, RequisitionState.receivingPart.getValue());
        } else {
            updateRequisitionState(requisitionId, RequisitionState.receiving.getValue());
        }

    }

    /**
     * 完成接单
     * @param detailId
     */
    public void CompleteOrderDetail(Long requisitionId,Long detailId){
        requisitionDetailService.updateRequisitionDetail(detailId, RequisitionDetailState.completed.getValue());
        List<Integer> states = Lists.newArrayList();
        states.add(RequisitionDetailState.pay.getValue());
        states.add(RequisitionDetailState.receiving.getValue());
        int count = requisitionDetailService.findByStateCount(requisitionId,states);
        if (count <= 0) {
            updateRequisitionState(requisitionId, RequisitionState.completed.getValue());
        }
    }

}
